[POI2010]MOS-Bridges

2020-02-03
POI

题意

在无向联通图中,每条无向边正向和反向权值不同,将其全部定向,使得存在从1开始的欧拉回路

求该回路上边权最大值的最小值,输出方案

题解

二分答案转化为判定性问题

先贪心地定向,按照较小的来,然后调整反向边,使这个图符合度数限制,网络流判定(把度数给别人)

输出方案的时候,同一次遍历中,晚遍历的边晚访问;不同次的遍历中,晚遍历的边早访问

两个deque维护即可

调试记录

输出方案挂了好几次,一开始没有考虑两种情况

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
#include <cstdio>
#include <queue>
#include <cstring>
#include <algorithm>
const int maxn = 2005;
const int S = 0;
const int T = 2001;
const int INF = 0x3f3f3f3f;
using namespace std;
struct E{
int to, nxt, f;
}e[maxn << 4]; int now[maxn], head[maxn], tot = 1;
void addedge(int u, int v, int f){
e[++tot].to = v, e[tot].nxt = head[u], e[tot].f = f;
head[u] = tot;
}
void ins(int u, int v, int f){
addedge(u, v, f); addedge(v, u, 0);
}
int dep[maxn];
bool bfs(){
queue <int> q; while (!q.empty()) q.pop(); q.push(S);
memset(dep, 0, sizeof dep); dep[S] = 1;
while (!q.empty()){
int cur = q.front(); q.pop();
for (int i = head[cur]; i; i = e[i].nxt){
int v = e[i].to;
if (dep[v] == 0 && e[i].f > 0){
dep[v] = dep[cur] + 1;
q.push(v);
}
}
}
return dep[T] > 0;
}
int dfs(int cur, int Max){
if (cur == T) return Max;
int flow = 0;
for (int i = head[cur]; i; i = e[i].nxt){
int v = e[i].to;
if (e[i].f > 0 && dep[v] == dep[cur] + 1){
int tmp = dfs(v, min(Max - flow, e[i].f));
flow += tmp;
e[i].f -= tmp;
e[i ^ 1].f += tmp;
if (flow == Max) return flow;
}
}
return flow;
}
int maxflow;
void Dinic(){
maxflow = 0;
while (bfs()) maxflow += dfs(S, INF);
}
int n, m, u[maxn], v[maxn], a[maxn], b[maxn];
int Min = INF, Max = 0, dex[maxn], last[maxn];
bool check(int mid){
memset(dex, 0, sizeof dex);
tot = 1; memset(head, 0, sizeof head);
for (int i = 1; i <= m; i++){
if (a[i] > mid && b[i] > mid) return false;
if (a[i] <= mid) dex[u[i]]--, dex[v[i]]++;
if (b[i] <= mid) ins(v[i], u[i], 1), last[i] = tot - 1;
else last[i] = 0;
} int sum = 0;
for (int i = 1; i <= n; i++){
if (dex[i] & 1) return false;
if (dex[i] > 0) ins(S, i, dex[i] >> 1), sum += dex[i];
else ins(i, T, (-dex[i]) >> 1);
}
Dinic();
return maxflow == (sum >> 1);
}
namespace SPJ{
struct E{
int to, nxt;
}e[::maxn << 1]; int head[maxn], dex[maxn], tot = 0;
void addedge(int u, int v){
e[++tot].to = v, e[tot].nxt = head[u];
head[u] = tot; ++dex[u]; ++dex[v];
}
bool vis[maxn];
deque <pair<int, int> > v[maxn], t[maxn];
void dfs(int cur){
if (dex[cur] == 0) return;
dex[cur]--;
for (int i = head[cur]; i; i = e[i].nxt){
if (!vis[i]){
vis[i] = 1; t[cur].push_back(make_pair(i,e[i].to));
dex[e[i].to]--; dfs(e[i].to);
break;
}
}
}
void solve(){
for (int i = 1; i <= ::n; i++){
if (dex[i] != 0) dfs(i);
for (int j = 1; j <= n; j++)
while (!t[j].empty()){
// if (j == 2) printf("%d\n", t[j].back().first);
v[j].push_front(t[j].back()), t[j].pop_back();
}
}
int cur = 1;
while (!v[cur].empty()){
printf("%d ", v[cur].front().first); int tmp = v[cur].front().second;
v[cur].pop_front(); cur = tmp;
} puts("");
}
}
int main(){
scanf("%d%d", &n, &m);
for (int i = 1; i <= m; i++){
scanf("%d%d%d%d", u + i, v + i, a + i, b + i);
Min = min(Min, min(a[i], b[i])); Max = max(Max, max(a[i], b[i]));
if (a[i] > b[i]) swap(u[i], v[i]), swap(a[i], b[i]);
}
int l = Min, r = Max, ans = -1;
while (l <= r){
int mid = l + r >> 1;
if (check(mid)){
ans = mid, r = mid - 1;
memset(SPJ::head, 0, sizeof SPJ::head); SPJ::tot = 0;
memset(SPJ::dex, 0, sizeof SPJ::dex);
for (int i = 1; i <= m; i++)
if (last[i] != 0 && e[last[i]].f == 0) SPJ::addedge(v[i], u[i]);
else SPJ::addedge(u[i], v[i]);
}
else l = mid + 1;
}
if (ans == -1) puts("NIE");
else printf("%d\n", ans);
if (ans != -1) SPJ::solve();
return 0;
}
/*
5 6
1 2 1 100
2 3 1 100
3 1 1 100
2 4 1 100
4 5 1 100
5 2 1 100
*/